#include"tcp.hpp"

using std::string;
using std::cerr;
using std::endl;
class tcpServer
{
    public:
        tcpServer(uint16_t port,const string& ip="")
            :_port(port)
            ,_ip(ip){}
        ~tcpServer()
        {}
        void Init()
        {
            _LiSockFd=socket(AF_INET,SOCK_STREAM,0);
            if(_LiSockFd<0)
            {
                logMessage(FATAL,"socket() failed::%s : %d",strerror(errno),_LiSockFd);
                exit(SOCKET_ERR);
            }
            logMessage(DEBUG,"socket() success::%d",_LiSockFd);
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));
            local.sin_family=AF_INET;
            local.sin_port=htons(_port);
            _ip.empty()?(local.sin_addr.s_addr=htonl(INADDR_ANY)):(inet_aton(_ip.c_str(),&local.sin_addr));
            
            if(bind(_LiSockFd,(const struct sockaddr*)&local,sizeof(local))==-1)
            {
                logMessage(FATAL,"socket() failed::%s : %d",strerror(errno),_LiSockFd);
                exit(BIND_ERR);
            }
            logMessage(DEBUG,"bind() success::%d",_LiSockFd);

            if(listen(_LiSockFd,5)==-1)
            {
                logMessage(FATAL,"listen() failed::%s : %d",strerror(errno),_LiSockFd);
                exit(LISTEN_ERR);
            }
            logMessage(DEBUG,"listen() success::%d",_LiSockFd);
        }
        void to_upper(int sock,const string& clientIP,const uint16_t &clientPort)
        {
            assert(sock>0);
            assert(!clientIP.empty());
            
            char inbuffer[BUFFER_SIZE];
            while(true)
            {
                ssize_t s=read(sock,inbuffer,sizeof(inbuffer)-1);
                if(s>0)
                {
                    inbuffer[s]='\0';
                    if(strcasecmp(inbuffer,"quit")==0)
                    {
                        logMessage(DEBUG,"Client requests to quit: [%s: %d]",clientIP.c_str(),clientPort);
                        break;
                    }
                    logMessage(DEBUG,"to_upper before:[%s:%d]>> %s",clientIP.c_str(),clientPort,inbuffer);
                    for(int i=0;i<s;i++)
                    {
                        if(isalpha(inbuffer[i])&&islower(inbuffer[i]))
                            inbuffer[i]=toupper(inbuffer[i]);
                    }
                    logMessage(DEBUG,"to_upper after:[%s:%d]>>%s",clientIP.c_str(),clientPort,inbuffer);
                    write(sock,inbuffer,strlen(inbuffer));
                }
                else if(s==0)
                {
                    logMessage(DEBUG,"Client has quited:[%s:%d]",clientIP.c_str(),clientPort);
                    break;
                }
                else{
                    logMessage(DEBUG,"Client [%s:%d] read::%s",clientIP.c_str(),clientPort,strerror(errno));
                    break; 
                }
            }
            close(sock);
            logMessage(DEBUG,"Service close %d sockFd",sock);
        }
        void start()
        {
            while(true)
            {
                struct sockaddr_in peer;
                socklen_t peerlen=sizeof(peer);
                
                int serviceSockFd=accept(_LiSockFd,(struct sockaddr*)&peer,&peerlen);
                if(serviceSockFd==-1)
                {
                    logMessage(WARINING,"accept() failed::%s : %d",strerror(errno),_LiSockFd);
                    continue;
                }
                string peerIp=inet_ntoa(peer.sin_addr);
                uint16_t peerPort=ntohs(peer.sin_port);
                logMessage(DEBUG,"accept() success:: [%s: %d] | %d",peerIp.c_str(),peerPort,serviceSockFd);
                to_upper(serviceSockFd,peerIp,peerPort);
            }
        }
    private:
        uint16_t _port;
        string _ip;
        int _LiSockFd;
};

void Usage(string proc)
{
    cerr<<"Usage::\n\t"<<proc<<"port ip"<<endl;
    cerr<<"example::\n\t"<<proc<<"8080 127.0.0.1"<<endl;
}

int main(int argc,char* argv[])
{
    if(argc!=3&&argc!=2)
    {
        Usage(argv[0]);
        exit(USE_ERR);
    }
    uint16_t port=atoi(argv[1]);
    string ip;
    if(argc==3)
    {
        ip=argv[2];
    }
    tcpServer Usvr(port,ip);
    Usvr.Init();
    Usvr.start();
    return 0;
}












